﻿using DoNetDrive.Common;
using DoNetDrive.Common.Cryptography;
using DoNetDrive.Common.Extensions;
using DoNetDrive.Core;
using DoNetDrive.Core.Command;
using DoNetDrive.Core.Command.Byte;
using DoNetDrive.Core.Connector;
using DoNetDrive.Core.Connector.UDP;
using DoNetDrive.Core.Packet;
using DoNetDrive.Protocol.OnlineAccess;
using DoNetDrive.Protocol.Packet;
using DotNetty.Buffers;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Newtonsoft.Json;

namespace UDPAgency
{
    public partial class Form1 : Form
    {
        ConnectorAllocator Allocator;
        private UDPAgenncyOption _option;
        private HashSet<string> ClientIPs;
        private Dictionary<string, AgencyItem> Agencies;
        private AgencyItem mAgencyItem;
        private bool mIsOpen;
        public Form1()
        {
            InitializeComponent();
            Trace.Listeners.Add(new MyTraceListener());
            _option = new UDPAgenncyOption();
            Agencies = new Dictionary<string, AgencyItem>();
        }

        private void ButBegin_Click(object sender, EventArgs e)
        {
            _option.UserPacketLose = chkpacketloss.Checked;
            _option.PacketLoseNum = (int)(txtLoseNum.Value);
            _option.ClearLosePacketCount();

            mAgencyItem = SaveAgencyItem();

            ClientIPs.Clear();
            if (!mIsOpen)
                OpenUDPServer();
            else
                CloseUDPServer();

        }

        private AgencyItem SaveAgencyItem()
        {
            var Item = new AgencyItem();
            Item.Name = txtName.Text;
            Item.LocalIP = cmbIP.Text;
            Item.LocalPort = int.Parse(txtLocalPort.Text);
            Item.RemoteIP = txtRemoteIP.Text;
            Item.RemotePort = int.Parse(txtRemotePort.Text);
            Item.RemoteLocalIP = cmbRemoteLocalIP.Text;
            Item.RemoteLocalPort = int.Parse(txtRemoteLocalPort.Text);
            var sKey = Item.ToString();
            Agencies[sKey] = Item;

            cmbDef.Items.Clear();
            cmbDef.Items.AddRange(Agencies.Values.ToArray());
            return Item;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            SetButtonEnabled(true);
            IniAllocator();
            mIsOpen = false;
            LoadLocalIP();
            LoadSetting();
            ClientIPs = new HashSet<string>();

        }


        #region 配置文件


        string mSettingFile;


        string mAgencyItemFile;
        /// <summary>
        /// 加载配置文件
        /// </summary>
        private void LoadSetting()
        {

            cmbDef.Items.Clear();
            Agencies.Clear();
            mAgencyItemFile = System.IO.Path.Combine(Application.StartupPath, "AgencySetting.xml");
            if (File.Exists(mAgencyItemFile))
            {
                var sJson = File.ReadAllText(mAgencyItemFile);
                var lstAgency = JsonConvert.DeserializeObject<AgencyItem[]>(sJson);
                cmbDef.Items.AddRange(lstAgency);
                foreach (var item in lstAgency)
                {
                    Agencies[item.ToString()] = item;
                }

            }




            mSettingFile = System.IO.Path.Combine(Application.StartupPath, "setting.xml");
            if (File.Exists(mSettingFile))
            {
                var xml = new MyXML(mSettingFile);
                xml.SelectDocumentElement("Main");
                xml.SelectElement("Value");

                var sValue = xml.GetValue("UsePacketloss", string.Empty);
                if (!string.IsNullOrEmpty(sValue))
                {
                    _option.UserPacketLose = bool.Parse(sValue);
                }

                sValue = xml.GetValue("PacketlossNum", string.Empty);
                if (!string.IsNullOrEmpty(sValue))
                {
                    _option.PacketLoseNum = int.Parse(sValue);
                }
            }

            chkpacketloss.Checked = _option.UserPacketLose;
            txtLoseNum.Value = _option.PacketLoseNum;


        }

        /// <summary>
        /// 保存配置文件
        /// </summary>
        private void SaveSetting()
        {

            var oItems = cmbDef.Items.Cast<AgencyItem>().ToArray();
            var sJson = JsonConvert.SerializeObject(oItems);
            File.WriteAllText(mAgencyItemFile, sJson);


            var xml = new MyXML(mSettingFile);
            xml.SelectDocumentElement("Main");
            xml.SelectElement("Value");


            _option.UserPacketLose = chkpacketloss.Checked;
            _option.PacketLoseNum = (int)txtLoseNum.Value;

            xml.SetValue("UsePacketloss", _option.UserPacketLose.ToString());
            xml.SetValue("PacketlossNum", _option.PacketLoseNum.ToString());
            xml.Save(mSettingFile);
            xml = null;
        }
        #endregion


        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            if (Allocator != null)
            {
                Allocator?.Dispose();
                Allocator = null;
                System.Threading.Thread.Sleep(2000);
            }
            SaveSetting();
        }




        private List<DoNetDrive.Core.Connector.TCPClient.TCPClientDetail> mAgencyMap;

        private void IniAllocator()
        {
            Allocator = ConnectorAllocator.GetAllocator();
            Allocator.ConnectorConnectedEvent += mAllocator_ConnectorConnectedEvent;
            Allocator.ConnectorErrorEvent += mAllocator_ConnectorErrorEvent;
            Allocator.ConnectorClosedEvent += Allocator_ConnectorClosedEvent;
            mAgencyMap = new List<DoNetDrive.Core.Connector.TCPClient.TCPClientDetail>();
        }



        /// <summary>
        /// 关闭本地UDP端口
        /// </summary>
        private void CloseUDPServer()
        {
            SetButtonEnabled(false);
            DoNetDrive.Core.Connector.UDP.UDPServerDetail serverDtl =
    new DoNetDrive.Core.Connector.UDP.UDPServerDetail(mAgencyItem.LocalIP, mAgencyItem.LocalPort);
            Allocator.CloseConnector(serverDtl);

            serverDtl =
    new DoNetDrive.Core.Connector.UDP.UDPServerDetail(mAgencyItem.RemoteLocalIP, mAgencyItem.RemoteLocalPort);
            Allocator.CloseConnector(serverDtl);

            mAgencyMap.Clear();

        }

        /// <summary>
        /// 绑定本地UDP端口
        /// </summary>
        private void OpenUDPServer()
        {


            
            SetButtonEnabled(false);
            DoNetDrive.Core.Connector.UDP.UDPServerDetail serverDtl =
                new DoNetDrive.Core.Connector.UDP.UDPServerDetail(mAgencyItem.LocalIP, mAgencyItem.LocalPort);

            Allocator.OpenConnector(serverDtl);

            serverDtl =
                new DoNetDrive.Core.Connector.UDP.UDPServerDetail(mAgencyItem.RemoteLocalIP, mAgencyItem.RemoteLocalPort);

            Allocator.OpenConnector(serverDtl);
        }
        public void Invoke(Action act)
        {
            try
            {
                this.Invoke((Delegate)act);

            }
            catch (Exception)
            {

                return;
            }


        }
        private void mAllocator_ConnectorErrorEvent(object sender, INConnectorDetail connector)
        {
            switch (connector.GetTypeName())
            {
                case ConnectorType.UDPServer://UDP服务器
                    Invoke(() => UDPBindOver(false));
                    break;
                default:
                    break;
            }
        }
        private void mAllocator_ConnectorConnectedEvent(object sender, INConnectorDetail connector)
        {
            switch (connector.GetTypeName())
            {
                case ConnectorType.UDPServer://UDP服务器
                    Invoke(() => UDPBindOver(true));
                    break;
                case ConnectorType.UDPClient:
                    var Dtl = (DoNetDrive.Core.Connector.TCPClient.TCPClientDetail)connector;
                    var INCon = Allocator.GetConnector(connector);
                    INCon.OpenForciblyConnect();

                    string sKey = $"{Dtl.Addr}:{Dtl.Port}";

                    if (ClientIPs.Contains(sKey))
                        return;
                    ClientIPs.Add(sKey);

                    //Trace.WriteLine($"连接建立：{Dtl}");
                    if (Dtl.Addr == mAgencyItem.RemoteIP && Dtl.Port == mAgencyItem.RemotePort)
                    {
                        INCon.AddRequestHandle(new IORemoteHandle(mAgencyMap, mAgencyItem.LocalIP, mAgencyItem.LocalPort, _option));
                    }
                    else
                    {
                        mAgencyMap.Add(Dtl);
                        INCon.AddRequestHandle(new IOAgencyHandle(mAgencyItem));
                    }

                    break;
                default:
                    break;
            }
        }






        private void Allocator_ConnectorClosedEvent(object sender, INConnectorDetail connector)
        {
            switch (connector.GetTypeName())
            {
                case ConnectorType.UDPServer://UDP服务器
                    Invoke(() => UDPCloseOver());
                    break;

                default:
                    break;
            }
        }

        private void UDPCloseOver()
        {
            SetButtonEnabled(true);
            butBegin.Text = "启动";
            mIsOpen = false;
            ShowTip("UDP服务器已关闭！");
        }

        /// <summary>
        /// 通道绑定成功
        /// </summary>
        /// <param name="bOver"></param>
        private void UDPBindOver(bool bOver)
        {
            if (!bOver)
            {
                SetButtonEnabled(true);
                butBegin.Text = "启动";
                mIsOpen = false;
                ShowTip("UDP服务器开启失败！");
            }
            else
            {
                SetButtonEnabled(false);
                butBegin.Text = "关闭";
                butBegin.Enabled = true;
                mIsOpen = true;
                ShowTip("UDP服务器开启成功！");
            }
        }

        private void ShowTip(string sLog)
        {
            Console.WriteLine(sLog);
            if (txtTip.InvokeRequired)
            {
                Invoke(() => txtTip.Text = sLog);
                return;
            }
            txtTip.Text = sLog;
        }

        private void SetButtonEnabled(bool bValue)
        {
            cmbIP.Enabled = bValue;
            txtLocalPort.Enabled = bValue;
            txtRemoteIP.Enabled = bValue;
            txtRemotePort.Enabled = bValue;
            butBegin.Enabled = bValue;

        }


        #region 本地IP列表加载与选择
        /// <summary>
        /// 记载本机IP
        /// </summary>
        private void LoadLocalIP()
        {
            var IPs = Dns.GetHostEntry(Dns.GetHostName());
            string sIP;
            cmbIP.Items.Clear();
            cmbIP.Items.Add("127.0.0.1");
            cmbIP.Items.Add("[::]");

            cmbRemoteLocalIP.Items.Clear();
            cmbRemoteLocalIP.Items.Add("127.0.0.1");
            cmbRemoteLocalIP.Items.Add("[::]");

            foreach (IPAddress oItem in IPs.AddressList)
            {

                sIP = oItem.ToString();
                if (sIP != "0.0.0.0")
                {
                    cmbIP.Items.Add(sIP);
                    cmbRemoteLocalIP.Items.Add(sIP);
                }


            }

            if ((cmbIP.Items.Count > 0))
                cmbIP.SelectedIndex = 0;

            if ((cmbRemoteLocalIP.Items.Count > 0))
                cmbRemoteLocalIP.SelectedIndex = 0;

        }


        #endregion

        private void CmbDef_SelectedIndexChanged(object sender, EventArgs e)
        {
            AgencyItem dtl = cmbDef.SelectedItem as AgencyItem;
            if (dtl == null) return;
            txtName.Text = dtl.Name;
            cmbIP.Text = dtl.LocalIP;
            txtLocalPort.Text = dtl.LocalPort.ToString();

            txtRemoteIP.Text = dtl.RemoteIP;
            txtRemotePort.Text = dtl.RemotePort.ToString();

            cmbRemoteLocalIP.Text = dtl.RemoteLocalIP;
            txtRemoteLocalPort.Text = dtl.RemoteLocalPort.ToString();
        }

        private void chkpacketloss_CheckedChanged(object sender, EventArgs e)
        {
            _option.UserPacketLose = chkpacketloss.Checked;

        }

        private void txtLoseNum_ValueChanged(object sender, EventArgs e)
        {
            _option.PacketLoseNum = (int)(txtLoseNum.Value);
        }

        private void tmrShowCount_Tick(object sender, EventArgs e)
        {
            txtLosePacketCount.Text = _option.LosePacketCount.ToString();
        }
    }
}
